#include "RockFall.h"
#include "PlayState.h"
#include "PauseState.h"
#include "MenuState.h"
#include "InstuctionState.h"
#include "WinState.h"
#include <stdlib.h>
#include <xact3.h>

RockFall::RockFall(HINSTANCE hInstance, int nShowCmd)
  : Game(hInstance, nShowCmd),
    stateMachine(this)
{
	EntityManager::init();
	LevelManager::init();
	MessageHandler::init();
	AnimationPlayer::AnimationPlayer();
	ForceRegistry::init();
	stateMachine.addState("StartMenu", new MenuState());
	stateMachine.addState("Instructions", new InstuctionState());
	stateMachine.addState("PauseMenu", new PauseState());
	stateMachine.addState("Play", new PlayState());
	stateMachine.addState("Winning", new WinState());
	stateMachine.changeState("StartMenu");
	startPause = false;
	prevLevel = 2;
}

RockFall::~RockFall()
{
}

void RockFall::loadContent()
{
	/**
	 * Create menus from texture files.
	 */
#pragma region MENUS
	D3DXCreateTextureFromFileEx(device, L"menuBG.png",
		D3DX_DEFAULT_NONPOW2, D3DX_DEFAULT_NONPOW2,
		0, 0, D3DFMT_FROM_FILE, D3DPOOL_DEFAULT,
		D3DX_DEFAULT, D3DX_DEFAULT,
		0, 0, 0, &backgroundText);
	D3DXCreateTextureFromFileEx(device, L"smStartOn.png",
		D3DX_DEFAULT_NONPOW2, D3DX_DEFAULT_NONPOW2,
		0, 0, D3DFMT_FROM_FILE, D3DPOOL_DEFAULT,
		D3DX_DEFAULT, D3DX_DEFAULT,
		0, 0, 0, &smStartOn);
	D3DXCreateTextureFromFileEx(device, L"smInstructionOn.png",
		D3DX_DEFAULT_NONPOW2, D3DX_DEFAULT_NONPOW2,
		0, 0, D3DFMT_FROM_FILE, D3DPOOL_DEFAULT,
		D3DX_DEFAULT, D3DX_DEFAULT,
		0, 0, 0, &smInstructionOn);
	D3DXCreateTextureFromFileEx(device, L"smExitOn.png",
		D3DX_DEFAULT_NONPOW2, D3DX_DEFAULT_NONPOW2,
		0, 0, D3DFMT_FROM_FILE, D3DPOOL_DEFAULT,
		D3DX_DEFAULT, D3DX_DEFAULT,
		0, 0, 0, &smExitOn);
	D3DXCreateTextureFromFileEx(device, L"pmResumeOn.png",
		D3DX_DEFAULT_NONPOW2, D3DX_DEFAULT_NONPOW2,
		0, 0, D3DFMT_FROM_FILE, D3DPOOL_DEFAULT,
		D3DX_DEFAULT, D3DX_DEFAULT,
		0, 0, 0, &pmResumeOn);
	D3DXCreateTextureFromFileEx(device, L"pmInstructionOn.png",
		D3DX_DEFAULT_NONPOW2, D3DX_DEFAULT_NONPOW2,
		0, 0, D3DFMT_FROM_FILE, D3DPOOL_DEFAULT,
		D3DX_DEFAULT, D3DX_DEFAULT,
		0, 0, 0, &pmInstructionOn);
	D3DXCreateTextureFromFileEx(device, L"pmExitOn.png",
		D3DX_DEFAULT_NONPOW2, D3DX_DEFAULT_NONPOW2,
		0, 0, D3DFMT_FROM_FILE, D3DPOOL_DEFAULT,
		D3DX_DEFAULT, D3DX_DEFAULT,
		0, 0, 0, &pmExitOn);
	D3DXCreateTextureFromFileEx(device, L"Instuctions.png",
		D3DX_DEFAULT_NONPOW2, D3DX_DEFAULT_NONPOW2,
		0, 0, D3DFMT_FROM_FILE, D3DPOOL_DEFAULT,
		D3DX_DEFAULT, D3DX_DEFAULT,
		0, 0, 0, &instuctions);
	D3DXCreateTextureFromFileEx(device, L"Winning.png",
		D3DX_DEFAULT_NONPOW2, D3DX_DEFAULT_NONPOW2,
		0, 0, D3DFMT_FROM_FILE, D3DPOOL_DEFAULT,
		D3DX_DEFAULT, D3DX_DEFAULT,
		0, 0, 0, &winning);
	D3DXCreateTextureFromFileEx(device, L"Losing.png",
		D3DX_DEFAULT_NONPOW2, D3DX_DEFAULT_NONPOW2,
		0, 0, D3DFMT_FROM_FILE, D3DPOOL_DEFAULT,
		D3DX_DEFAULT, D3DX_DEFAULT,
		0, 0, 0, &losing);

	startMenu = new Menus(backgroundText, smStartOn, smInstructionOn, smExitOn);
	pauseMenu = new Menus(backgroundText, pmResumeOn, pmInstructionOn, pmExitOn);
	instrcutionScreen = new Menus(backgroundText, instuctions, NULL, NULL);
	winScreen = new Menus(backgroundText, winning, losing, NULL);
#pragma endregion

	/**
	 * Create tile set. Used for creating levels
	 */
#pragma region TILESET
	D3DXCreateTextureFromFileEx(device, L"tileset.png", D3DX_DEFAULT_NONPOW2, D3DX_DEFAULT_NONPOW2,
		0, 0, D3DFMT_FROM_FILE, D3DPOOL_DEFAULT,
		D3DX_DEFAULT, D3DX_DEFAULT,
		0, 0, 0, &tiles);
	std::string names = "abcdefghijkl"; //chars used in level*.txt each tile
	D3DSURFACE_DESC desc;
	tiles->GetLevelDesc(0, &desc);
	int tileWidth = desc.Width / 4;		// Assumes TileSet is 4 tiles wide
	int tileHeight = desc.Height / 3;	// and 3 Tiles high.
	tileSet = new TileSet(names, tiles, tileWidth, tileHeight);
	
	device->GetViewport(&viewport);
#pragma endregion

	/**
	 * Create levels from imported txt file and tile set. Register with 
	 * level manager. Each level has a start and end point assosiated
	 * with it that are hardcoded when the level is created, these
	 * points are assosiated with the level switcher entities.
	 */
#pragma region LEVELS
	// Create levels
	level00 = Level::createLevel(tileSet, "level000.txt", viewport,
		D3DXVECTOR3(200, 220, 0),	// Level start point.
		D3DXVECTOR3(2940, 1620, 0),	// Level end point.
		D3DXVECTOR3(0, 0, 0));	// Initial level offset.
	level01 = Level::createLevel(tileSet, "level001.txt", viewport,
		D3DXVECTOR3(240, 1750, 0),	// Level start point.
		D3DXVECTOR3(400, 220, 0),	// Level end point.
		D3DXVECTOR3(0, 0, 0));		// Initial level offset.
	level02 = Level::createLevel(tileSet, "level02.txt", viewport,
		D3DXVECTOR3(128, 400, 0),
		D3DXVECTOR3(384, -50, 0),
		D3DXVECTOR3(0, 0, 0));
	// Register with LevelManager.
	LevelManager::registerLevel(level00);
	LevelManager::registerLevel(level01);
	LevelManager::registerLevel(level02);

	// Set current Level.
	LevelManager::setCurrentID(0);
	prevLevel = LevelManager::getCurrentID();
	// Set initial position of top left corner of current Level.
	levelPosition = LevelManager::getCurrentLevel()->getOffset();
#pragma endregion

	/**
	 * Load level switcher textures from file.
	 */
#pragma region LEVELSWITCHERS
	D3DXCreateTextureFromFileEx(device, L"StartSign.png",
		D3DX_DEFAULT_NONPOW2, D3DX_DEFAULT_NONPOW2,
		0, 0, D3DFMT_FROM_FILE, D3DPOOL_DEFAULT,
		D3DX_DEFAULT, D3DX_DEFAULT,
		0, 0, 0, &startTexture);
	D3DXCreateTextureFromFileEx(device, L"EndSign.png",
		D3DX_DEFAULT_NONPOW2, D3DX_DEFAULT_NONPOW2,
		0, 0, D3DFMT_FROM_FILE, D3DPOOL_DEFAULT,
		D3DX_DEFAULT, D3DX_DEFAULT,
		0, 0, 0, &endTexture);
	// Initialise level swithcers as level start and end points.
	startPoint = new LevelSwitcher(LevelManager::getCurrentLevel()->getStartPoint(),
		startTexture, 1000);
	endPoint = new LevelSwitcher(LevelManager::getCurrentLevel()->getEndPoint(),
		endTexture, 1001);
#pragma endregion

	/** Create ladder entites, this will need updated when multiple levels
	 * change the positions of the ladders.
	 */
#pragma region LADDERS
	// Load the ladder texture.
	D3DXCreateTextureFromFileEx(device, L"Ladder.png",
		D3DX_DEFAULT_NONPOW2, D3DX_DEFAULT_NONPOW2,
		0, 0, D3DFMT_FROM_FILE, D3DPOOL_DEFAULT,
		D3DX_DEFAULT, D3DX_DEFAULT,
		0, 0, 0, &ladderTexture);
	
	// Initialise level 0 ladder positions.
	int x000[] = {136, 136, 136, 264, 264, 264, 2952, 2824, 2312, 648, 520, 648};
	int y000[] = {832, 1216, 1600, 640, 1024, 1408, 960, 768, 1024, 1536, 1344, 1152};
	// Add ladders to level 0 ladder list.
	for (int i = 0; i < (sizeof(x000) / sizeof(int)) ; i++)
	{
		Ladder* tempLadder = new Ladder(D3DXVECTOR3(x000[i], y000[i], 0), ladderTexture, 0);
		ladders0.push_back(tempLadder);
	}
	
	// Initialise level 1 ladder positions.
	int x001[] = {136, 136, 392, 1480, 1800, 1992, 2248, 2312, 2504, 2632, 3016, 3016, 3016, 3016};
	int y001[] = {320, 512, 1216, 1536, 960, 704, 1536, 384, 960, 1536, 576, 1216, 1408, 1600};
	// Add ladders to level 1 ladder list.
	for (int i = 0; i < (sizeof(x001) / sizeof(int)) ; i++)
	{
		Ladder* tempLadder = new Ladder(D3DXVECTOR3(x001[i], y001[i], 0), ladderTexture, 1);
		tempLadder->setAlive(false);
		ladders1.push_back(tempLadder);
	}

	// Initialise level 2 ladder positions.
	int x002[] = {72, 712};
	int y002[] = {320, 320};
	// Add ladders to level 2 ladder list.
	for (int i = 0; i < (sizeof(x002) / sizeof(int)) ; i++)
	{
		Ladder* tempLadder = new Ladder(D3DXVECTOR3(x002[i], y002[i], 0), ladderTexture, 1);
		tempLadder->setAlive(false);
		ladders2.push_back(tempLadder);
	}
#pragma endregion

	/**
	 * Create player, load each animation texture, make and animation
	 * from that texture. Load all animations into animation player and
	 * create the player object.
	 */
#pragma region PLAYER
	D3DXCreateTextureFromFileEx(device, L"Attack.png",
		D3DX_DEFAULT_NONPOW2, D3DX_DEFAULT_NONPOW2,
		0, 0, D3DFMT_FROM_FILE, D3DPOOL_DEFAULT,
		D3DX_DEFAULT, D3DX_DEFAULT,
		0, 0, 0, &attackTexture);
	D3DXCreateTextureFromFileEx(device, L"Climb.png", 
		D3DX_DEFAULT_NONPOW2, D3DX_DEFAULT_NONPOW2,
		0, 0, D3DFMT_FROM_FILE, D3DPOOL_DEFAULT,
		D3DX_DEFAULT, D3DX_DEFAULT,
		0, 0, 0, &climbTexture);
	D3DXCreateTextureFromFileEx(device, L"Die.png",
		D3DX_DEFAULT_NONPOW2, D3DX_DEFAULT_NONPOW2,
		0, 0, D3DFMT_FROM_FILE, D3DPOOL_DEFAULT,
		D3DX_DEFAULT, D3DX_DEFAULT,
		0, 0, 0, &dieTexture);
	D3DXCreateTextureFromFileEx(device, L"Idle.png",
		D3DX_DEFAULT_NONPOW2, D3DX_DEFAULT_NONPOW2,
		0, 0, D3DFMT_FROM_FILE, D3DPOOL_DEFAULT,
		D3DX_DEFAULT, D3DX_DEFAULT,
		0, 0, 0, &idleTexture);
	D3DXCreateTextureFromFileEx(device, L"Interact.png",
		D3DX_DEFAULT_NONPOW2, D3DX_DEFAULT_NONPOW2,
		0, 0, D3DFMT_FROM_FILE, D3DPOOL_DEFAULT,
		D3DX_DEFAULT, D3DX_DEFAULT,
		0, 0, 0, &interactTexture);
	D3DXCreateTextureFromFileEx(device, L"Jump.png",
		D3DX_DEFAULT_NONPOW2, D3DX_DEFAULT_NONPOW2,
		0, 0, D3DFMT_FROM_FILE, D3DPOOL_DEFAULT,
		D3DX_DEFAULT, D3DX_DEFAULT,
		0, 0, 0, &jumpTexture);
	D3DXCreateTextureFromFileEx(device, L"Run.png",
		D3DX_DEFAULT_NONPOW2, D3DX_DEFAULT_NONPOW2,
		0, 0, D3DFMT_FROM_FILE, D3DPOOL_DEFAULT,
		D3DX_DEFAULT, D3DX_DEFAULT,
		0, 0, 0, &runTexture);

	// Load textures from files.
	Animation* attackAnim = new Animation(attackTexture);
	attackAnim->setIsLooping(false);
	Animation* climbAnim = new Animation(climbTexture);
	Animation* dieAnim = new Animation(dieTexture);
	dieAnim->setIsLooping(false);
	Animation* idleAnim = new Animation(idleTexture);
	Animation* interactAnim = new Animation(interactTexture);
	Animation* jumpAnim = new Animation(jumpTexture);
	jumpAnim->setIsLooping(false);
	Animation* runAnim = new Animation(runTexture);

	// Create animations from textures.
	AnimationPlayer* playerAnims = new AnimationPlayer();
	playerAnims->addAnimation("Attack", attackAnim);
	playerAnims->addAnimation("Climb", climbAnim);
	playerAnims->addAnimation("Die", dieAnim);
	playerAnims->addAnimation("Idle", idleAnim);
	playerAnims->addAnimation("Interact", interactAnim);
	playerAnims->addAnimation("Jump", jumpAnim);
	playerAnims->addAnimation("Run", runAnim);

	// Current player animation.
	playerAnims->playAnimation("Idle");

	// Create the player object.
	player = new Player(playerAnims, LevelManager::getCurrentLevel());
#pragma endregion

	/**
	 * Load the weapon textures.
	 */
#pragma region WEAPONS
	D3DXCreateTextureFromFileEx(device, L"Rock.png",
		D3DX_DEFAULT_NONPOW2, D3DX_DEFAULT_NONPOW2,
		0, 0, D3DFMT_FROM_FILE, D3DPOOL_DEFAULT,
		D3DX_DEFAULT, D3DX_DEFAULT,
		0, 0, 0, &rockTexture);
	D3DXCreateTextureFromFileEx(device, L"Melle.png",
		D3DX_DEFAULT_NONPOW2, D3DX_DEFAULT_NONPOW2,
		0, 0, D3DFMT_FROM_FILE, D3DPOOL_DEFAULT,
		D3DX_DEFAULT, D3DX_DEFAULT,
		0, 0, 0, &melleTexture);
#pragma endregion

	/**
	 * Create enemies from texture files and initialise zones
	 */
#pragma region BATS
	// Load bat animation textures from files.
	D3DXCreateTextureFromFileEx(device, L"BatIdle.png",
		D3DX_DEFAULT_NONPOW2, D3DX_DEFAULT_NONPOW2,
		0, 0, D3DFMT_FROM_FILE, D3DPOOL_DEFAULT,
		D3DX_DEFAULT, D3DX_DEFAULT,
		0, 0, 0, &batIdleTexture);
	D3DXCreateTextureFromFileEx(device, L"BatAttack.png",
		D3DX_DEFAULT_NONPOW2, D3DX_DEFAULT_NONPOW2,
		0, 0, D3DFMT_FROM_FILE, D3DPOOL_DEFAULT,
		D3DX_DEFAULT, D3DX_DEFAULT,
		0, 0, 0, &batAttackTexture);
	
	// Create animations from textures.
	Animation* BatIdle = new Animation(batIdleTexture);
	Animation* BatAttack = new Animation(batAttackTexture);

	/** Initialise bat enemy zone co-ords. */
#pragma region LEVEL0BATS
	// Initialise level 0 bat zone bounds, there are 4 zones in level 0.
	std::list<D3DXVECTOR3> batZone01;
	batZone01.push_back(D3DXVECTOR3(448,128,0));
	batZone01.push_back(D3DXVECTOR3(960,256,0));
	batZones0[1] = batZone01;
	std::list<D3DXVECTOR3> batZone02;
	batZone02.push_back(D3DXVECTOR3(128,448,0));
	batZone02.push_back(D3DXVECTOR3(1216,576,0));
	batZones0[2] = batZone02;
	std::list<D3DXVECTOR3> batZone03;
	batZone03.push_back(D3DXVECTOR3(649,1024,0));
	batZone03.push_back(D3DXVECTOR3(1216,1216,0));
	batZones0[3] = batZone03;
	std::list<D3DXVECTOR3> batZone04;
	batZone04.push_back(D3DXVECTOR3(1156,1408,0));
	batZone04.push_back(D3DXVECTOR3(2304,1536,0));
	batZones0[4] = batZone04;

	// Number of bats per zone.
	numBats = 5;

	// Add a number of bats to each zone with random positions.
	for (int z = 1; z <= 4; z++)
	{
		// Get zone bounds for this zone.
		D3DXVECTOR3 topLeft = batZones0[z].front();
		D3DXVECTOR3 bottomRight = batZones0[z].back();
		for (int i = 0; i < numBats; ++i)
		{
			// Create animation from file 
			AnimationPlayer* batAnims = new AnimationPlayer();
			batAnims->addAnimation("Idle", BatIdle);
			batAnims->addAnimation("Attack", BatAttack);
			batAnims->playAnimation("Idle");

			// Randomly generate position of bat with in the zone.
			int randX = rand() % (int)(bottomRight.x - topLeft.x) + (int)topLeft.x;
			int randY = rand() % (int)(bottomRight.y - topLeft.y) + (int)topLeft.y;
			D3DXVECTOR3 tempPos(randX, randY, 0);
			// Create the bat and add to list of bats.
			BatEnemy* tempBat = new BatEnemy(batAnims, tempPos,	topLeft , bottomRight);
			bats0.push_back(tempBat);
		}
	}
#pragma endregion
	
#pragma region LEVEL1BATS
	// Initialise level 1 bat zone bounds, there are *** zones in level 1.
	std::list<D3DXVECTOR3> batZone11;
	batZone11.push_back(D3DXVECTOR3(576,1728,0));
	batZone11.push_back(D3DXVECTOR3(1408,1792,0));
	batZones1[1] = batZone11;
	std::list<D3DXVECTOR3> batZone12;
	batZone12.push_back(D3DXVECTOR3(192,1024,0));
	batZone12.push_back(D3DXVECTOR3(2176,320,0));
	batZones1[2] = batZone12;
	std::list<D3DXVECTOR3> batZone13;
	batZone13.push_back(D3DXVECTOR3(640,1208,0));
	batZone13.push_back(D3DXVECTOR3(1664,1400,0));
	batZones1[3] = batZone13;
	std::list<D3DXVECTOR3> batZone14;
	batZone14.push_back(D3DXVECTOR3(3008,1088,0));
	batZone14.push_back(D3DXVECTOR3(3136,1750,0));
	batZones1[4] = batZone14;
	std::list<D3DXVECTOR3> batZone15;
	batZone15.push_back(D3DXVECTOR3(2560,640,0));
	batZone15.push_back(D3DXVECTOR3(3136,870,0));
	batZones1[5] = batZone15;

	// Number of bats per zone.
	numBats = 5;

	// Add a number of bats to each zone with random positions.
	for (int z = 1; z <= 5; z++)
	{
		// Get zone bounds for this zone.
		D3DXVECTOR3 topLeft = batZones1[z].front();
		D3DXVECTOR3 bottomRight = batZones1[z].back();
		for (int i = 0; i < numBats; ++i)
		{
			// Create animation from file 
			AnimationPlayer* batAnims = new AnimationPlayer();
			batAnims->addAnimation("Idle", BatIdle);
			batAnims->addAnimation("Attack", BatAttack);
			batAnims->playAnimation("Idle");

			// Randomly generate position of bat with in the zone.
			int randX = rand() % (int)(bottomRight.x - topLeft.x) + (int)topLeft.x;
			int randY = rand() % (int)(bottomRight.y - topLeft.y) + (int)topLeft.y;
			D3DXVECTOR3 tempPos(randX, randY, 0);
			// Create the bat and add to list of bats.
			BatEnemy* tempBat = new BatEnemy(batAnims, tempPos,	topLeft , bottomRight);
			tempBat->setAlive(false);
			bats1.push_back(tempBat);
		}
	}
#pragma endregion
#pragma endregion

#pragma region YETI
	//Yeti enemy animation
	D3DXCreateTextureFromFileEx(device, L"YetiIdle.png",
		D3DX_DEFAULT_NONPOW2, D3DX_DEFAULT_NONPOW2,
		0, 0, D3DFMT_FROM_FILE, D3DPOOL_DEFAULT,
		D3DX_DEFAULT, D3DX_DEFAULT,
		0, 0, 0, &yetiIdleTexture);
	D3DXCreateTextureFromFileEx(device, L"YetiMove.png",
		D3DX_DEFAULT_NONPOW2, D3DX_DEFAULT_NONPOW2,
		0, 0, D3DFMT_FROM_FILE, D3DPOOL_DEFAULT,
		D3DX_DEFAULT, D3DX_DEFAULT,
		0, 0, 0, &yetiMoveTexture);
	D3DXCreateTextureFromFileEx(device, L"YetiAttack.png",
		D3DX_DEFAULT_NONPOW2, D3DX_DEFAULT_NONPOW2,
		0, 0, D3DFMT_FROM_FILE, D3DPOOL_DEFAULT,
		D3DX_DEFAULT, D3DX_DEFAULT,
		0, 0, 0, &yetiAttackTexture);
	D3DXCreateTextureFromFileEx(device, L"YetiHit.png",
		D3DX_DEFAULT_NONPOW2, D3DX_DEFAULT_NONPOW2,
		0, 0, D3DFMT_FROM_FILE, D3DPOOL_DEFAULT,
		D3DX_DEFAULT, D3DX_DEFAULT,
		0, 0, 0, &yetiHitTexture);
	D3DXCreateTextureFromFileEx(device, L"YetiDie.png",
		D3DX_DEFAULT_NONPOW2, D3DX_DEFAULT_NONPOW2,
		0, 0, D3DFMT_FROM_FILE, D3DPOOL_DEFAULT,
		D3DX_DEFAULT, D3DX_DEFAULT,
		0, 0, 0, &yetiDieTexture);
#pragma endregion
	/**
	 * Create render target textures and surfaces used for lighting effect.
	 */
#pragma region RENDERTARGETS
	mRTSone = 0;
	D3DXCreateRenderToSurface(
		device,
		800, 600,
		D3DFMT_A8R8G8B8,
		false,
		D3DFMT_UNKNOWN,
		&mRTSone);
	mTexOne = 0;
	D3DXCreateTexture(
		device,
		800, 600,
		D3DX_DEFAULT,
		D3DUSAGE_RENDERTARGET,
		D3DFMT_A8R8G8B8,
		D3DPOOL_DEFAULT,
		&mTexOne);
	mTopSurfOne = 0;

	mRTStwo = 0;
	D3DXCreateRenderToSurface(
		device,
		800, 600,
		D3DFMT_A8R8G8B8,
		false,
		D3DFMT_UNKNOWN,
		&mRTStwo);
	mTexTwo = 0;
	D3DXCreateTexture(
		device,
		800, 600,
		D3DX_DEFAULT,
		D3DUSAGE_RENDERTARGET,
		D3DFMT_A8R8G8B8,
		D3DPOOL_DEFAULT,
		&mTexTwo);
	mTopSurfTwo = 0;
#pragma endregion

	/**
	 * Initialise stuff for lighting effect
	 */
#pragma region LIGHTING
	D3DXCreateTextureFromFileEx(device, L"Light.png",
		D3DX_DEFAULT_NONPOW2, D3DX_DEFAULT_NONPOW2,
		0, 0, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT,
		D3DX_DEFAULT, D3DX_DEFAULT,
		0, 0, 0, &torch);
	D3DXCreateTextureFromFileEx(device, L"Clear.png",
		D3DX_DEFAULT_NONPOW2, D3DX_DEFAULT_NONPOW2,
		0, 0, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT,
		D3DX_DEFAULT, D3DX_DEFAULT,
		0, 0, 0, &clear);

	ID3DXBuffer* errors = 0;
	D3DXCreateEffectFromFile(device,
							 L"LightingEffect.fx",
							 0,
							 0,
							 D3DXSHADER_DEBUG,
							 0,
							 &lightEffect,
							 &errors);
	if (errors)
		MessageBoxA(0, (char*)errors->GetBufferPointer(), 0, 0);


	lightTexture = lightEffect->GetParameterByName(0, "AlphaTexture");
	gameTexture = lightEffect->GetParameterByName(0, "ScreenTexture");
	time = lightEffect->GetParameterByName(0, "time");
	technique = lightEffect->GetTechniqueByName("Lighting");

	D3DVERTEXELEMENT9 VertexPTElements[] =
	{
		{0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
		{0, 12, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
		D3DDECL_END()
	};
	device->CreateVertexDeclaration(VertexPTElements, &decl);

	device->CreateVertexBuffer(6 * sizeof(VertexPosTex), 
							   D3DUSAGE_WRITEONLY, 
							   0, 
							   D3DPOOL_MANAGED, 
							   &vertexBuffer, 
							   0);
	VertexPosTex* v = 0;
	vertexBuffer->Lock(0, 0, (void**)&v, 0);
	v[0] = VertexPosTex(D3DXVECTOR3(-1, 1, 0), D3DXVECTOR2(0, 0));
	v[1] = VertexPosTex(D3DXVECTOR3(1, 1, 0), D3DXVECTOR2(1, 0));
	v[2] = VertexPosTex(D3DXVECTOR3(-1, -1, 0), D3DXVECTOR2(0, 1));
	v[3] = VertexPosTex(D3DXVECTOR3(-1, -1, 0), D3DXVECTOR2(0, 1));
	v[4] = VertexPosTex(D3DXVECTOR3(1, 1, 0), D3DXVECTOR2(1, 0));
	v[5] = VertexPosTex(D3DXVECTOR3(1, -1, 0), D3DXVECTOR2(1, 1));
	vertexBuffer->Unlock();

	device->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
#pragma endregion
}

void RockFall::update(float frameTime)
{
	// Check for input.
	inputHandler->poll();

	/**
	 * Check input handler for input and set menu, play, action states.
	 */
#pragma region MENUCONTROLS
	// Enter pause menu when escape is pressed & in plat state.
	if (inputHandler->isKeyDown(DIK_ESCAPE) &&
		stateMachine.getCurrentState() == stateMachine.getState("Play"))
		stateMachine.changeState("PauseMenu");

	// Handles input during start menu state.
#pragma region STARTMENU
	if (stateMachine.getCurrentState() == stateMachine.getState("StartMenu"))
	{
		if (inputHandler->isKeyDown(DIK_UP) && !inputHandler->wasKeyDown(DIK_UP))
		{
			if (startMenu->getCurrentSlide() > 1)
				startMenu->setCurrentSlide(startMenu->getCurrentSlide() - 1);
		}
		else if (inputHandler->isKeyDown(DIK_DOWN) && !inputHandler->wasKeyDown(DIK_DOWN))
		{
			if (startMenu->getCurrentSlide() < 3)
				startMenu->setCurrentSlide(startMenu->getCurrentSlide() + 1);
		}
		else if (inputHandler->isKeyDown(DIK_RETURN) && !inputHandler->wasKeyDown(DIK_RETURN))
		{
			switch (startMenu->getCurrentSlide())
			{
			case 1:
				// Enter play state.
				stateMachine.changeState("Play");
				break;
			case 2:
				// Show instruction screen.
				stateMachine.changeState("Instructions");
				startPause = false;
				break;
			case 3:
				// Exit application.
				PostQuitMessage(0);
				break;
			}
		}
	}
#pragma endregion

	// Handles input during pause menu state.
#pragma region PAUSEMENU
	if (stateMachine.getCurrentState() == stateMachine.getState("PauseMenu"))
	{
		if (inputHandler->isKeyDown(DIK_UP) && !inputHandler->wasKeyDown(DIK_UP))
		{
			if (pauseMenu->getCurrentSlide() > 1)
				pauseMenu->setCurrentSlide(pauseMenu->getCurrentSlide() - 1);
		}
		else if (inputHandler->isKeyDown(DIK_DOWN) && !inputHandler->wasKeyDown(DIK_DOWN))
		{
			if (pauseMenu->getCurrentSlide() < 3)
				pauseMenu->setCurrentSlide(pauseMenu->getCurrentSlide() + 1);
		}
		else if (inputHandler->isKeyDown(DIK_RETURN) && !inputHandler->wasKeyDown(DIK_RETURN))
		{
			switch (pauseMenu->getCurrentSlide())
			{
			case 1:
				// Enter play state.
				stateMachine.changeState("Play");
				break;
			case 2:
				// Show instruction screen.
				stateMachine.changeState("Instructions");
				startPause = true;
				break;
			case 3:
				// Exit application.
				PostQuitMessage(0);
				break;
			}
		}
	}
#pragma endregion

	// Handler input during instruction screen.
#pragma region INSTRUCTIONS
	if (stateMachine.getCurrentState() == stateMachine.getState("Instructions"))
	{
		if (inputHandler->isKeyDown(DIK_RETURN) && !inputHandler->wasKeyDown(DIK_RETURN))
		{
			if (startPause)
				stateMachine.changeState("PauseMenu");
			else
				stateMachine.changeState("StartMenu");
		}
	}
#pragma endregion

	// Handles input during win screen state.
#pragma region WINSCREEN
	if (stateMachine.getCurrentState() == stateMachine.getState("Winning"))
	{
		if (inputHandler->isKeyDown(DIK_RETURN) && !inputHandler->wasKeyDown(DIK_RETURN))
		{
			if (winScreen->getCurrentSlide() == 1)
				stateMachine.changeState("StartMenu");
			if (winScreen->getCurrentSlide() == 2)
				stateMachine.changeState("PauseMenu");
		}
	}
#pragma endregion
#pragma endregion

	/**
	 * Check that the player stays within the bounds of the window.
	 */
#pragma region PLAYERBOUNDS
	if (LevelManager::getCurrentID() != 2)
	{
		if (player->getPosition().x < 100)
		{
			levelPosition.x += player->getPosition().x - 100;
			player->setPosition(D3DXVECTOR3(100, player->getPosition().y, 0));
		}
		else if (player->getPosition().x > 600)
		{
			levelPosition.x += player->getPosition().x - 600;
			player->setPosition(D3DXVECTOR3(600, player->getPosition().y, 0));
		}
		if (player->getPosition().y < 100)
		{
			levelPosition.y += player->getPosition().y - 100;
			player->setPosition(D3DXVECTOR3(player->getPosition().x, 100, 0));
		}
		else if (player->getPosition().y > 400)
		{
			levelPosition.y += player->getPosition().y - 400;
			player->setPosition(D3DXVECTOR3(player->getPosition().x, 400, 0));
		}
	}
#pragma endregion

	/**
	 * Load level switcher entites when level changes.
	 */
#pragma region LEVELSWITCHERS
	startPoint->setPosition(-levelPosition + 
		LevelManager::getCurrentLevel()->getStartPoint());
	endPoint->setPosition(-levelPosition + 
		LevelManager::getCurrentLevel()->getEndPoint());
#pragma endregion

	/**
	 * When the level changes stop displaying ladders and enemies 
	 * currently being displayed and display the current level ladders 
	 * and enemies.
	 */
#pragma region SWICHLEVELENTITES
	// Check if the current level differs from the previous level.
	if (LevelManager::getCurrentID() == 2 && 
		(EntityManager::getEntity(2000) == NULL))
	{
		//Load textures from file
		Animation* yetiIdleAnims = new Animation(yetiIdleTexture);
		Animation* yetiMoveAnims = new Animation(yetiMoveTexture);
		Animation* yetiAttackAnims = new Animation(yetiAttackTexture);
		yetiAttackAnims->setIsLooping(false);
		Animation* yetiHitAnims = new Animation(yetiHitTexture);
		Animation* yetiDieAnims = new Animation(yetiDieTexture);
		yetiDieAnims->setIsLooping(false);

		//Create animations from texture
		AnimationPlayer* yetiAnims = new AnimationPlayer();
		yetiAnims->addAnimation("Idle", yetiIdleAnims);
		yetiAnims->addAnimation("Move", yetiMoveAnims);
		yetiAnims->addAnimation("Attack", yetiAttackAnims);
		yetiAnims->addAnimation("Hit", yetiHitAnims);
		yetiAnims->addAnimation("Die", yetiDieAnims);
		yetiAnims->playAnimation("Idle");

		yeti = new YetiEnemy(yetiAnims,
						D3DXVECTOR3(650, 400, 0),
						LevelManager::getLevel(2));
	}
	if (prevLevel != LevelManager::getCurrentID())
	{
		switch (LevelManager::getCurrentID())
		{
		case 0: // Set previous level ladders alive parameter to false
				// and therefore stop them being displayed.
			for (int i=0; i < ladders2.size(); i++)
			{
				Ladder* ladder = ladders2.front();
				ladder->setAlive(false);
				ladders2.pop_front();
				ladders2.push_back(ladder);
			}	// Set the current level ladder alive to true
				// to display them.
			for (int i=0; i < ladders0.size(); i++)
			{
				Ladder* ladder = ladders0.front();
				ladder->setAlive(true);
				ladders0.pop_front();
				ladders0.push_back(ladder);
			}
			for (int i=0; i < bats0.size(); i++)
			{
				BatEnemy* bat = bats0.front();
				bat->setAlive(true);
				bats0.pop_front();
				bats0.push_back(bat);
			}
			prevLevel = LevelManager::getCurrentID();
			break;
		case 1:	// Do the same for the next level.
			for (int i=0; i < ladders0.size(); i++)
			{
				Ladder* ladder = ladders0.front();
				ladder->setAlive(false);
				ladders0.pop_front();
				ladders0.push_back(ladder);
			}
			for (int i=0; i < ladders1.size(); i++)
			{
				Ladder* ladder = ladders1.front();
				ladder->setAlive(true);
				ladders1.pop_front();
				ladders1.push_back(ladder);
			}
			for (int i=0; i < bats0.size(); i++)
			{
				BatEnemy* bat = bats0.front();
				bat->setAlive(false);
				bats0.pop_front();
				bats0.push_back(bat);
			}
			for (int i=0; i < bats1.size(); i++)
			{
				BatEnemy* bat = bats1.front();
				bat->setAlive(true);
				bats1.pop_front();
				bats1.push_back(bat);
			}
			prevLevel = LevelManager::getCurrentID();
			break;
		case 2:	// And again for the last level.
			for (int i=0; i < ladders1.size(); i++)
			{
				Ladder* ladder = ladders1.front();
				ladder->setAlive(false);
				ladders1.pop_front();
				ladders1.push_back(ladder);
			}
			for (int i=0; i < ladders2.size(); i++)
			{
				Ladder* ladder = ladders2.front();
				ladder->setAlive(true);
				ladders2.pop_front();
				ladders2.push_back(ladder);
			}
			for (int i=0; i < bats1.size(); i++)
			{
				BatEnemy* bat = bats1.front();
				bat->setAlive(false);
				bats1.pop_front();
				bats1.push_back(bat);
			}
			prevLevel = LevelManager::getCurrentID();
			
			break;
		}
	}
#pragma endregion

	/**
	 * Load & remove enemies when the level changes.
	 */

	/**
	 * Update game assets managers that deal with all game objects.
	 */
#pragma region UPDATEASSETS
	// Set the current level offset.
	LevelManager::getCurrentLevel()->setOffset(levelPosition);
	// Depending on current state the state machine handles the 
	// updates required in that state.
	stateMachine.update(frameTime);
#pragma endregion
}

void RockFall::render()
{
	/**
	 * Draw level and entities to render target one.
	 */
#pragma region RENDERTARGET1
	mTexOne->GetSurfaceLevel(0, &mTopSurfOne);

	mRTSone->BeginScene(mTopSurfOne, &viewport);
	device->Clear(0,
				  NULL,
				  D3DCLEAR_TARGET,
				  D3DCOLOR_ARGB(0, 0, 0, 0),
				  1.0f,
				  0);
	sprite->Begin(D3DXSPRITE_ALPHABLEND);

	// Draw game textures here.
	stateMachine.draw(sprite);

	sprite->End();
	mRTSone->EndScene(0);
#pragma endregion

	/**
	 * Draw effects to render target two.
	 */
#pragma region RENDERTARGET2
	mTexTwo->GetSurfaceLevel(0, &mTopSurfTwo);

	mRTStwo->BeginScene(mTopSurfTwo, &viewport);
	device->Clear(0,
				  NULL,
				  D3DCLEAR_TARGET,
				  D3DCOLOR_ARGB(0, 0, 0, 0),
				  1.0f,
				  0);
	sprite->Begin(D3DXSPRITE_ALPHABLEND);
	
	// Draw effects here.
	if (LevelManager::getCurrentID() < 2)
	{
		D3DXVECTOR3 playerPos = EntityManager::getNamedEntities("Player")->front()->getPosition() - D3DXVECTOR3(96, 96, 0);
		D3DXVECTOR3 torchPos = playerPos - D3DXVECTOR3(48, 48, 0);
		sprite->Draw(torch, 0, 0, &torchPos, D3DCOLOR_XRGB(255,255,255));
	}
	else
		sprite->Draw(clear, 0, 0, &D3DXVECTOR3(0, 0, 0), D3DCOLOR_XRGB(255, 255, 255));

	sprite->End();
	mRTStwo->EndScene(0);
#pragma endregion

	/**
	 * Draw combined render target to the back buffer,
	 * and therefore the screen
	 */
#pragma region BACKBUFFER
	device->BeginScene();

	if ((stateMachine.getCurrentState() == stateMachine.getState("Play")) &&
		(LevelManager::getCurrentID() < 2))
	{
		device->Clear(0,
					  0,
					  D3DCLEAR_TARGET,
					  D3DCOLOR_ARGB(255, 255, 255, 255),
					  1.0f,
					  0);
	
		device->SetStreamSource(0, vertexBuffer, 0, sizeof(VertexPosTex));
		device->SetVertexDeclaration(decl);

		lightEffect->SetTechnique(technique);
		lightEffect->SetTexture(gameTexture, mTexOne);
		lightEffect->SetTexture(lightTexture, mTexTwo);
		lightEffect->SetFloat(time, 1.0f);

		UINT numPasses = 0;
		lightEffect->Begin(&numPasses, 0);
		for (UINT i = 0; i < numPasses; ++i)
		{
			lightEffect->BeginPass(i);
			device->DrawPrimitive(D3DPT_TRIANGLELIST, 0, 2);
			lightEffect->EndPass();
		}
	}
	else
	{
		device->Clear(0,
					  0,
					  D3DCLEAR_TARGET,
					  D3DCOLOR_ARGB(255, 0, 0, 0),
					  1.0f,
					  0);
		sprite->Begin(D3DXSPRITE_ALPHABLEND);
		sprite->Draw(mTexOne, 0, 0, &D3DXVECTOR3(0, 0, 0), D3DCOLOR_XRGB(255, 255, 255));
		sprite->End();
	}

	device->EndScene();
	device->Present(0, 0, 0, 0);
#pragma endregion
}

void RockFall::unloadContent()
{
#pragma region TEXTURES
	backgroundText->Release();
	backgroundText = 0;
	smStartOn->Release();
	smStartOn = 0;
	smInstructionOn->Release();
	smInstructionOn = 0;
	smExitOn->Release();
	smExitOn = 0;
	pmResumeOn->Release();
	pmResumeOn = 0;
	pmInstructionOn->Release();
	pmInstructionOn = 0;
	pmExitOn->Release();
	pmExitOn = 0;
	//rockTexture->Release();
	//rockTexture = 0;
	tiles->Release();
	tiles = 0;
	startTexture->Release();
	startTexture = 0;
	endTexture->Release();
	endTexture = 0;
	attackTexture->Release();
	attackTexture = 0;
	climbTexture->Release();
	climbTexture = 0;
	dieTexture->Release();
	dieTexture = 0;
	idleTexture->Release();
	idleTexture = 0;
	interactTexture->Release();
	interactTexture = 0;
	jumpTexture->Release();
	jumpTexture = 0;
	runTexture->Release();
	runTexture = 0;
	batIdleTexture->Release();
	batIdleTexture = 0;
	batAttackTexture->Release();
	batAttackTexture = 0;
	yetiIdleTexture->Release();
	yetiIdleTexture = 0;
	yetiMoveTexture->Release();
	yetiMoveTexture = 0;
	yetiAttackTexture->Release();
	yetiAttackTexture = 0;
	yetiHitTexture->Release();
	yetiHitTexture = 0;
	yetiDieTexture->Release();
	yetiDieTexture = 0;
	mRTSone->Release();
	mRTSone = 0;
	mTexOne->Release();
	mTexOne = 0;
	mTopSurfOne->Release();
	mTopSurfOne = 0;
	mRTStwo->Release();
	mRTStwo = 0;
	mTexTwo->Release();
	mTexTwo = 0;
	mTopSurfTwo->Release();
	mTopSurfTwo = 0;
#pragma endregion
	// Unload other entity textures HERE...
}